﻿@page "/Account/Manage/ExternalLogins"

@using Microsoft.AspNetCore.Authentication
@using Microsoft.AspNetCore.Identity
@using MyApp.Data

@inject UserManager<ApplicationUser> UserManager
@inject SignInManager<ApplicationUser> SignInManager
@inject IdentityUserAccessor UserAccessor
@inject IUserStore<ApplicationUser> UserStore
@inject IdentityRedirectManager RedirectManager

<PageTitle>Manage your external logins</PageTitle>

<div class="max-w-xl">
    <StatusMessage class="mb-3" />
    @if (currentLogins?.Count > 0)
    {
        <Heading3>Registered Logins</Heading3>
        <div class="prose prose-xl">
            <table class="table">
                <tbody>
                    @foreach (var login in currentLogins)
                    {
                        <tr>
                            <td id="login-provider-@login.LoginProvider"><Heading4>@login.ProviderDisplayName</Heading4></td>
                            <td>
                                @if (showRemoveButton)
                                {
                                    <form id="remove-login-@login.LoginProvider" @formname="@($"remove-login-{login.LoginProvider}")" @onsubmit="OnSubmitAsync" method="post">
                                        <AntiforgeryToken />
                                        <div>
                                            <input type="hidden" name="@nameof(LoginProvider)" value="@login.LoginProvider" />
                                            <input type="hidden" name="@nameof(ProviderKey)" value="@login.ProviderKey" />
                                            <PrimaryButton type="submit" title=@($"Remove this {login.ProviderDisplayName} login from your account")>Remove</PrimaryButton>
                                        </div>
                                    </form>
                                }
                                else
                                {
                                    @: &nbsp;
                                }
                            </td>
                        </tr>
                    }
                </tbody>
            </table>
        </div>
    }
    @if (otherLogins?.Count > 0)
    {
        <Heading4>Add another service to log in.</Heading4>
        <form id="link-login-form" class="mt-4 form-horizontal" action="Account/Manage/LinkExternalLogin" method="post">
            <AntiforgeryToken />
            <div id="socialLoginList">
                <p>
                    @foreach (var provider in otherLogins)
                    {
                        <button id="link-login-button-@provider.Name"
                                type="submit"
                                class="@SecondaryButton.Classes mr-2 mb-2"
                                name="Provider"
                                value="@provider.Name"
                                title="Log in using your @provider.DisplayName account">
                            @provider.DisplayName
                        </button>
                    }
                </p>
            </div>
        </form>
    }

</div>

@code {
    public const string LinkLoginCallbackAction = "LinkLoginCallback";

    private ApplicationUser user = default!;
    private IList<UserLoginInfo>? currentLogins;
    private IList<AuthenticationScheme>? otherLogins;
    private bool showRemoveButton;

    [CascadingParameter]
    private HttpContext HttpContext { get; set; } = default!;

    [SupplyParameterFromForm]
    private string? LoginProvider { get; set; }

    [SupplyParameterFromForm]
    private string? ProviderKey { get; set; }

    [SupplyParameterFromQuery]
    private string? Action { get; set; }

    protected override async Task OnInitializedAsync()
    {
        user = await UserAccessor.GetRequiredUserAsync(HttpContext);
        currentLogins = await UserManager.GetLoginsAsync(user);
        otherLogins = (await SignInManager.GetExternalAuthenticationSchemesAsync())
            .Where(auth => currentLogins.All(ul => auth.Name != ul.LoginProvider))
            .ToList();

        string? passwordHash = null;
        if (UserStore is IUserPasswordStore<ApplicationUser> userPasswordStore)
        {
            passwordHash = await userPasswordStore.GetPasswordHashAsync(user, HttpContext.RequestAborted);
        }

        showRemoveButton = passwordHash is not null || currentLogins.Count > 1;

        if (HttpMethods.IsGet(HttpContext.Request.Method) && Action == LinkLoginCallbackAction)
        {
            await OnGetLinkLoginCallbackAsync();
        }
    }

    private async Task OnSubmitAsync()
    {
        var result = await UserManager.RemoveLoginAsync(user, LoginProvider!, ProviderKey!);
        if (!result.Succeeded)
        {
            RedirectManager.RedirectToCurrentPageWithStatus("Error: The external login was not removed.", HttpContext);
        }

        await SignInManager.RefreshSignInAsync(user);
        RedirectManager.RedirectToCurrentPageWithStatus("The external login was removed.", HttpContext);
    }

    private async Task OnGetLinkLoginCallbackAsync()
    {
        var userId = await UserManager.GetUserIdAsync(user);
        var info = await SignInManager.GetExternalLoginInfoAsync(userId);
        if (info is null)
        {
            RedirectManager.RedirectToCurrentPageWithStatus("Error: Could not load external login info.", HttpContext);
        }

        var result = await UserManager.AddLoginAsync(user, info);
        if (!result.Succeeded)
        {
            RedirectManager.RedirectToCurrentPageWithStatus("Error: The external login was not added. External logins can only be associated with one account.", HttpContext);
        }

        // Clear the existing external cookie to ensure a clean login process
        await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme);

        RedirectManager.RedirectToCurrentPageWithStatus("The external login was added.", HttpContext);
    }
}
